package gw.com.android.presenter.http;

import android.text.TextUtils;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import gw.com.android.model.ConfigUtil;
import gw.com.android.ui.news.CalendarArgs;
import gw.com.android.utils.CacheUtils;
import okhttp3.Request;
import okhttp3.Response;
import www.com.library.interfaces.ReqCallBack;
import www.com.library.util.StringFormatter;

/**
 * @author jett
 * @since 2017-11-24.
 */
public class CalendarRequest {

    private final CalendarArgs args;

    private boolean cache = false;
    private final String cacheFileName = "_calendar.dat";

    public CalendarRequest(CalendarArgs args) {
        if (args != null) {
            cache = args.calendar == null;
        }
        this.args = args;
    }

    public List<CalendarData> fetchLocal() {
        String str = CacheUtils.readFile(cacheFileName);
        return parse(str, null);
    }

    public void call(final ReqCallBack<List<CalendarData>> callBack) {
        String url = ConfigUtil.instance().getUrlPath("calendarList");
        new Https(url).addParam("releaseTime", args.getTime()).get(new Https.ResponseCallback<String>() {
            @Override
            public void onSuccess(Request request, Response response, String result, int code) {
                List<CalendarData> datas = parse(result, args.types);
                if (callBack != null) {
                    callBack.onReqSuccess(datas);
                }
            }

            @Override
            public void onFailure(Request request, IOException e) {
                if (callBack != null) {
                    callBack.onReqFailed(e == null ? null : e.getMessage());
                }
            }
        });
    }

    private List<CalendarData> parse(String str, List<String> types) {
        if (TextUtils.isEmpty(str)) {
            return null;
        }
        str = str.substring(1);
        str = str.substring(0, str.length() - 1);
        try {
            JSONObject jsonObject = new JSONObject(str);
            if (localExpired(jsonObject)) {
                return null;
            }
            JSONObject responseJson = jsonObject.optJSONObject("data");
            if (responseJson != null) {
                List<CalendarData> list = new ArrayList<>();
                JSONArray dataArr = responseJson.optJSONArray("financeData");
                JSONArray eventArr = responseJson.optJSONArray("financeEvent");
                JSONArray vacationArr = responseJson.optJSONArray("financeVacation");

                boolean hasData = true;
                boolean hasEvent = true;
                boolean hasVacation = true;
                if (types != null && !types.isEmpty()) {
                    hasData = types.contains("1");
                    hasEvent = types.contains("2");
                    hasVacation = types.contains("3");
                }
                if (hasVacation && vacationArr != null && vacationArr.length() > 0) {
                    for (int i = 0; i < vacationArr.length(); i++) {
                        JSONObject vacationJson = vacationArr.optJSONObject(i);
                        CalendarData vacation = parseVacationJson(vacationJson);
                        if (vacation != null) {
                            list.add(vacation);
                        }
                    }
                }
                if (hasData && dataArr != null && dataArr.length() > 0) {
                    for (int i = 0; i < dataArr.length(); i++) {
                        JSONObject dataJson = dataArr.optJSONObject(i);
                        CalendarData data = parseDataJson(dataJson);
                        if (data != null) {
                            list.add(data);
                        }
                    }
                }
                if (hasEvent && eventArr != null && eventArr.length() > 0) {
                    for (int i = 0; i < eventArr.length(); i++) {
                        JSONObject eventJson = eventArr.optJSONObject(i);
                        CalendarData event = parseEventJson(eventJson);
                        if (event != null) {
                            list.add(event);
                        }
                    }
                }
                if (cache) {
                    jsonObject.put("local_expir", args == null ? null : args.getTime());
                    CacheUtils.writeFile(cacheFileName, jsonObject.toString());
                }
                Collections.sort(list, new CalendarComparetor());
                return list;
            }
        } catch (Exception ignore) {
        }
        return null;
    }

    private class CalendarComparetor implements Comparator<CalendarData> {

        @Override
        public int compare(CalendarData o1, CalendarData o2) {
            if (o1 == null || o2 == null) {
                return 0;
            }
            if (o1.isVacation) {
                if (o2.isVacation) {
                    return 0;
                } else {
                    return -1;
                }
            }
            if (o2.isVacation) {
                return 1;
            }
            if (TextUtils.isEmpty(o1.time)) {
                if (TextUtils.isEmpty(o2.time)) {
                    return 0;
                } else {
                    return -1;
                }
            }
            if (TextUtils.isEmpty(o2.time)) {
                return 1;
            }
            return o1.time.compareTo(o2.time);
        }

    }

    private boolean localExpired(JSONObject json) {
        String localExpir = json.optString("local_expir");
        if (!TextUtils.isEmpty(localExpir)) {
            String time = StringFormatter.instance().toDate(Calendar.getInstance().getTime());
            return !localExpir.equals(time);
        }
        return false;
    }

    private CalendarData parseDataJson(JSONObject json) {
        if (json != null) {
            CalendarData result = new CalendarData();
            result.isData = true;
            result.profitable = json.optString("profitable");
            result.dataStatus = json.optString("dataStatus");
            result.basicIndexId = json.optString("basicIndexId");
            result.time = json.optString("time");
            result.lastValue = json.optString("lastValue");
            result.predictValue = json.optString("predictValue");
            result.value = json.optString("value");
            result.date = json.optString("date");
            result.importanceLevel = json.optInt("importanceLevel");
            result.country = json.optString("country");
            result.name = json.optString("name");
            result.impactValue = json.optString("impactValue");
            //result.lastUpdateTime = json.optString("lastUpdateTime");
            return result;
        }
        return null;
    }

    private CalendarData parseEventJson(JSONObject json) {
        if (json != null) {
            CalendarData result = new CalendarData();
            result.isEvent = true;
            result.time = json.optString("time");
            result.date = json.optString("date");
            result.importanceLevel = json.optInt("importanceLevel");
            result.country = json.optString("country");
            //result.impactValue = json.optString("impactValue");
            //result.lastUpdateTime = json.optString("lastUpdateTime");
            //result.title = json.optString("title");
            //result.region = json.optString("region");
            result.content = json.optString("content");
            return result;
        }
        return null;
    }

    private CalendarData parseVacationJson(JSONObject json) {
        if (json != null) {
            CalendarData result = new CalendarData();
            result.isVacation = true;
            result.time = json.optString("time");
            result.date = json.optString("date");
            //result.importanceLevel = json.optInt("importanceLevel");
            result.country = json.optString("country");
            //result.impactValue = json.optString("impactValue");
            //result.lastUpdateTime = json.optString("lastUpdateTime");
            result.title = json.optString("title");
            //result.region = json.optString("region");
            result.content = json.optString("content");
            return result;
        }
        return null;
    }

    public class CalendarData {

        private boolean isData;
        private boolean isEvent;
        private boolean isVacation;

        public String profitable;
        public String dataStatus;
        public String basicIndexId;
        public String lastValue;
        public String predictValue;
        public String name;
        public String value;

        public String date;
        public String time;
        public int importanceLevel;
        public String country;
        public String impactValue;
        public String lastUpdateTime;
        public String title;
        public String region;
        public String content;

        public boolean isFinanceData() {
            return isData;
        }

        public boolean isFinanceEvent() {
            return isEvent;
        }

        public boolean isFinanceVacation() {
            return isVacation;
        }

    }

}
